package cn.dinkevin.xui.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.media.MediaMetadataRetriever;
import android.support.annotation.NonNull;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Bitmap 工具类
 * Created by Administrator on 2016/12/7 0007.
 */

public final class BitmapUtil {

    private BitmapUtil(){}

    /**
     * 将 Byte 数据填充到 Bitmap
     * @param data
     * @return
     */
    public static Bitmap fill(byte[] data){
        if(data != null && data.length != 0){
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }else{
            return null;
        }
    }

    /**
     * 压缩图片尺寸
     * @param srcPath   源图片路径
     * @param dstPath   压缩后目标路径
     * @param maxLength 最大边长（宽与高的最大值）
     */
    public static boolean compress(String srcPath,String dstPath,float maxLength){

        int angle = getImageSpinAngle(srcPath);
        BitmapFactory.Options options = new BitmapFactory.Options();
        // 开始读入图片，此时把 options.inJustDecodeBounds 设回true了
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(srcPath, options);
        options.inJustDecodeBounds = false;

        // 缩放图片的尺寸
        float w = options.outWidth;
        float h = options.outHeight;
        float hh = maxLength > 0 ? maxLength : 1024f;     //  默认高度最大值为 1024
        float ww = maxLength > 0 ? maxLength : 1024f;     //  默认宽度最大值为 1024
        // 最长宽度或高度1024
        float be = 1.0f;

        if (w > h && w > ww) {
            be = w / ww;
        } else if (w < h && h > hh) {
            be = h / hh;
        }

        if (be <= 0) {
            be = 1.0f;
        }

        options.inSampleSize = (int) be;// 设置缩放比例,这个数字越大,图片大小越小.
        // 重新读入图片，注意此时已经把options.inJustDecodeBounds 设回false了
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, options);
        int desWidth = (int) (w / be);
        int desHeight = (int) (h / be);
        if (bitmap==null) return false;

        // 压缩图片尺寸
        bitmap = Bitmap.createScaledBitmap(bitmap, desWidth, desHeight, true);
        if(null != bitmap){

            // 旋转图片
            bitmap = rotatingImage(angle,bitmap);

            // 创建文件
            if(!FileUtil.exist(dstPath)){
                FileUtil.create(dstPath);
            }

            // 写入压缩后的图片到指定路径
            saveImage(bitmap,dstPath,null);
            bitmap.recycle();
            return true;
        }
        return false;
    }

    /**
     * 保存图片到本地指定路径
     * @param bitmap 图片
     * @param dstFilePath 目标文件路径
     * @param format 图片格式，默认为 JPEG
     * @return true -> 保存成功；否则保存失败
     */
    public static boolean saveImage(Bitmap bitmap, String dstFilePath, Bitmap.CompressFormat format){
        if(null==bitmap) return false;

        if(FileUtil.create(dstFilePath)){
            OutputStream output = FileUtil.openFileOutputStream(dstFilePath);
            bitmap.compress(format == null ? Bitmap.CompressFormat.JPEG : format,60,output);
            FileUtil.closeStream(output);
        }
        return false;
    }

    /**
     * 截取指定时间的视频图像
     * @param videoFilePath 视频资源路径
     * @param frameTimePosition 指定帧时间
     * @return
     */
    public static Bitmap createVideoThumbnail(String videoFilePath,long frameTimePosition){

        Bitmap bitmap = null;
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(videoFilePath);
            bitmap = retriever.getFrameAtTime(frameTimePosition);
        } catch (IllegalArgumentException ex) {
        } catch (RuntimeException ex) {
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
            }
        }

        if (bitmap == null) return null;

        // Scale down the bitmap if it's too large.
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int max = Math.max(width, height);
        if (max > 512) {
            float scale = 512f / max;
            int w = Math.round(scale * width);
            int h = Math.round(scale * height);
            bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
        }
        return bitmap;
    }


    /**
     * bitmap中的透明色用白色替换
     *
     * @param bitmap
     * @return
     */
    public static Bitmap changeColor(Bitmap bitmap) {
        if (bitmap == null) {
            return null;
        }
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        int[] colorArray = new int[w * h];
        int n = 0;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int color = getMixtureWhite(bitmap.getPixel(j, i));
                colorArray[n++] = color;
            }
        }
        return Bitmap.createBitmap(colorArray, w, h, Bitmap.Config.ARGB_8888);
    }

    /**
     * 获取和白色混合颜色
     *
     * @return
     */
    private static int getMixtureWhite(int color) {
        int alpha = Color.alpha(color);
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        return Color.rgb(getSingleMixtureWhite(red, alpha), getSingleMixtureWhite

                        (green, alpha),
                getSingleMixtureWhite(blue, alpha));
    }
    /**
     * 获取单色的混合值
     *
     * @param color
     * @param alpha
     * @return
     */
    private static int getSingleMixtureWhite(int color, int alpha) {
        int newColor = color * alpha / 255 + 255 - alpha;
        return newColor > 255 ? 255 : newColor;
    }

    /**
     * 分享图片信息 将bitmap转为byte格式的数组
     */
    public static byte[] bmpToByteArray(final Bitmap bitmap, final boolean needRecycle) {
        //创建字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //Bitmap.compress()方法的参数format可设置JPEG或PNG格式；quality可选择压缩质量；fOut是输出流（OutputStream）
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        if (needRecycle) {
            bitmap.recycle();
        }
        //将字节数组输出流转为byte数组
        byte[] result = outputStream.toByteArray();
        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 基于 Luban 算法的图片压缩，默认采取 Luban 算法的第三级压缩</br>
     * 引用地址：https://github.com/Curzibn/Luban
     * @param sourceImagePath   源图片路径
     * @param dstImagePath      目标图片路径
     * @return
     */
    public static void compressLuban(@NonNull String sourceImagePath, @NonNull String dstImagePath) {

        double size;
        int angle = getImageSpinAngle(sourceImagePath);
        int width = getImageSize(sourceImagePath)[0];
        int height = getImageSize(sourceImagePath)[1];
        int thumbW = width % 2 == 1 ? width + 1 : width;
        int thumbH = height % 2 == 1 ? height + 1 : height;

        width = thumbW > thumbH ? thumbH : thumbW;
        height = thumbW > thumbH ? thumbW : thumbH;

        double scale = ((double) width / height);

        if (scale <= 1 && scale > 0.5625) {
            if (height < 1664) {
                if (sourceImagePath.length() / 1024 < 150){
                    FileUtil.copy(sourceImagePath,dstImagePath);
                    return;
                }

                size = (width * height) / Math.pow(1664, 2) * 150;
                size = size < 60 ? 60 : size;
            } else if (height >= 1664 && height < 4990) {
                thumbW = width / 2;
                thumbH = height / 2;
                size = (thumbW * thumbH) / Math.pow(2495, 2) * 300;
                size = size < 60 ? 60 : size;
            } else if (height >= 4990 && height < 10240) {
                thumbW = width / 4;
                thumbH = height / 4;
                size = (thumbW * thumbH) / Math.pow(2560, 2) * 300;
                size = size < 100 ? 100 : size;
            } else {
                int multiple = height / 1280 == 0 ? 1 : height / 1280;
                thumbW = width / multiple;
                thumbH = height / multiple;
                size = (thumbW * thumbH) / Math.pow(2560, 2) * 300;
                size = size < 100 ? 100 : size;
            }
        } else if (scale <= 0.5625 && scale > 0.5) {
            if (height < 1280 && sourceImagePath.length() / 1024 < 200) {
                FileUtil.copy(sourceImagePath,dstImagePath);
                return;
            }

            int multiple = height / 1280 == 0 ? 1 : height / 1280;
            thumbW = width / multiple;
            thumbH = height / multiple;
            size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400;
            size = size < 100 ? 100 : size;
        } else {
            int multiple = (int) Math.ceil(height / (1280.0 / scale));
            thumbW = width / multiple;
            thumbH = height / multiple;
            size = ((thumbW * thumbH) / (1280.0 * (1280 / scale))) * 500;
            size = size < 100 ? 100 : size;
        }

        Bitmap bitmap = compress(sourceImagePath,thumbW, thumbH);
        bitmap = rotatingImage(angle,bitmap);
        saveImage(dstImagePath,bitmap,(long) size);
    }

    /**
     * 保存图片到指定路径
     * Save image with specified size
     *
     * @param dstFilePath the image file saveImage path 储存路径
     * @param bitmap   the image what be saveImage   目标图片
     * @param size     the file size of image   期望大小，单位为 KB
     */
    public static File saveImage(String dstFilePath, Bitmap bitmap, long size) {

        File result = new File(dstFilePath.substring(0, dstFilePath.lastIndexOf("/")));

        if (!result.exists() && !result.mkdirs()) return null;

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        int options = 100;
        bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream);

        // 最大质量为35
        while (stream.toByteArray().length / 1024 > size && options > 35) {
            stream.reset();
            options -= 6;
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, stream);
        }
        bitmap.recycle();

        try {
            FileOutputStream fos = new FileOutputStream(dstFilePath);
            fos.write(stream.toByteArray());
            fos.flush();
            fos.close();
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new File(dstFilePath);
    }

    /**
     * 旋转图片
     * rotate the image with specified angle
     *
     * @param angle  the angle will be rotating 旋转的角度
     * @param bitmap target image               目标图片
     */
    public static Bitmap rotatingImage(int angle, Bitmap bitmap) {
        //rotate image
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);

        //create a new image
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }


    /**
     * obtain the thumbnail that specify the size
     *
     * @param imagePath the target image path
     * @param width     the width of thumbnail
     * @param height    the height of thumbnail
     * @return {@link Bitmap}
     */
    public static Bitmap compress(String imagePath, int width, int height) {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);

        int outH = options.outHeight;
        int outW = options.outWidth;
        int inSampleSize = 1;

        if (outH > height || outW > width) {
            int halfH = outH / 2;
            int halfW = outW / 2;

            while ((halfH / inSampleSize) > height && (halfW / inSampleSize) > width) {
                inSampleSize *= 2;
            }
        }

        options.inSampleSize = inSampleSize;

        options.inJustDecodeBounds = false;

        int heightRatio = (int) Math.ceil(options.outHeight / (float) height);
        int widthRatio = (int) Math.ceil(options.outWidth / (float) width);

        if (heightRatio > 1 || widthRatio > 1) {
            if (heightRatio > widthRatio) {
                options.inSampleSize = heightRatio;
            } else {
                options.inSampleSize = widthRatio;
            }
        }
        options.inJustDecodeBounds = false;

        return BitmapFactory.decodeFile(imagePath, options);
    }

    /**
     * obtain the image rotation angle
     * @param path path of target image
     */
    public static int getImageSpinAngle(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 获取图片的尺寸
     * obtain the image's width and height
     *
     * @param imagePath the path of image
     */
    public static int[] getImageSize(String imagePath) {
        int[] res = new int[2];

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 1;
        BitmapFactory.decodeFile(imagePath, options);

        res[0] = options.outWidth;
        res[1] = options.outHeight;

        return res;
    }
}
